/*
 * ChessPanel.java
 *
 * Created on 18. �erven 2007, 10:09
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package cz.possoft.client.chess.gui.panel;

import javax.swing.JApplet;

import cz.possoft.client.chess.gui.components.ChessPane;
import cz.possoft.client.chess.gui.components.PesecNaKonciDialog;
import cz.possoft.client.gui.dialog.SimpleDialog;
import cz.possoft.client.gui.panel.GamePanel;
import cz.possoft.client.gui.panel.nastavenispodnipanel.panel.NastaveniShowPanel;
import cz.possoft.generic.utils.GenericUtils;
import cz.possoft.messages.PropertiesManager;
import cz.possoft.messages.Text;
import cz.possoft.serializable.chess.figurky.Figurka;
import cz.possoft.serializable.chess.figurky.King;
import cz.possoft.serializable.chess.figurky.Pesec;
import cz.possoft.serializable.chess.figurky.Prazdna;
import cz.possoft.serializable.chess.game.ChessGame;
import cz.possoft.serializable.chess.game.ChessPole;
import cz.possoft.serializable.generic.Game;
import cz.possoft.serializable.generic.Location;

/**
 * Herni panel vlevo nahore, ktery slouzi ke hre sachy.
 * 
 * @author mara
 */
public class ChessPanel extends GamePanel { 

    // levy panel s ukazatelama cisel 1,2,3,...8
    private LeftUkazatelPanel leftUkazatelPanel;

    // spodni panel s ukazatelama pismen a,b,c,d...
    private SpodniUkazatelPanel spodniUkazatelPanel;    

    // implicitni konstruktor - volani super
    public ChessPanel() {    	
    }
    
    // volani super
    public ChessPanel(JApplet applet) {
    	super(applet);
    }    

    // inicializace komponent. Volani super a inicializace specifickych komponent
    protected void initComponents() {
    	super.initComponents();
        add(getLeftUkazatelPanel(), "1,2,1,4");        
        add(getSpodniUkazatelPanel(), "2,5,4,5");        
    }   

    // pomocna privatni metoda pro vraceni pretypovaneho gamePane
    private ChessPane getChessPane() {        
        return (ChessPane)getGamePane();
    }

    private LeftUkazatelPanel getLeftUkazatelPanel() {
        if (leftUkazatelPanel == null) {
            leftUkazatelPanel = new LeftUkazatelPanel();
        }
        return leftUkazatelPanel;
    }

    private SpodniUkazatelPanel getSpodniUkazatelPanel() {
        if (spodniUkazatelPanel == null) {
            spodniUkazatelPanel = new SpodniUkazatelPanel();
        }
        return spodniUkazatelPanel;
    }

    // pomocna privatni metoda. Vraci pretypovanou game.
    private ChessGame getChessGame() {
        return (ChessGame)getGame();
    }        

    // nastavi game a zpusobi prekresleni celeho obsahu panelu podle predane game
    public void setAndInitGame(Game gam) {
    	super.setAndInitGame(gam);
        ChessGame game = (ChessGame)gam;                 
        controlSachForEveryFigurka();
        setMarked(false);
        setMarkedFigurkaForPlay(new Location(-1, -1));
        setRingFigurka(new Location(-1, -1));        
        getChessPane().setWhitePlayer(game.isMeWhite());
        getLeftUkazatelPanel().setLabelsForColor(game.isMeWhite() ? GenericUtils.COLOR_WHITE : GenericUtils.COLOR_BLACK);
        getSpodniUkazatelPanel().setLabelsForColor(game.isMeWhite() ? GenericUtils.COLOR_WHITE : GenericUtils.COLOR_BLACK);
        getChessPane().setHraciPole(game.getSachovnice());
    }

    // vraci aktualni stav sachovnice
    // 1 - jsem bilej, jsem na tahu a jeste jsem neoznacil figurku
    // 2 - jsem cernej, jsem na tahu a jeste jsem neoznacil figurku
    // 3 - jsem bilej, jsem na tahu a figurka jiz byla oznacena
    // 4 - jsem cernej, jsem an tahu a figurka jiz byla oznacena
    // 5 - jsem bilej a protihrac je na tahu
    // 6 - jsem cernej a protihrac je na tahu
    // 7 - toto by logicky nemelo nastat
    public int getGameState() {
        if ((getChessGame().isMeWhite()) && (getChessGame().isWhiteNaTahu()) && (!isMarked())) {
            return 1;
        }
        if ((!getChessGame().isMeWhite()) && (!getChessGame().isWhiteNaTahu()) && (!isMarked())) {
            return 2;
        }
        if ((getChessGame().isMeWhite()) && (getChessGame().isWhiteNaTahu()) && (isMarked())) {
            return 3;
        }
        if ((!getChessGame().isMeWhite()) && (!getChessGame().isWhiteNaTahu()) && (isMarked())) {
            return 4;
        }
        if ((getChessGame().isMeWhite()) && (!getChessGame().isWhiteNaTahu())) {
            return 5;
        }
        if ((!getChessGame().isMeWhite()) && (getChessGame().isWhiteNaTahu())) {
            return 6;
        }
        // posledni moznost je teoreticka a nemela by nastat
        return 7;
    }


    // volano z motionListeneru pokud jsem na tahu a jeste neni oznacena figurka.
    // zpusobi oznaceni figurky ale jen cervenym prstencem. Nasetuje hodnotu oznaceni na figurku
    // s prstencem a z byvale figurky odstrani priznak prstence.
    // Pak prekresli sachovnici
    public void updateRingFigurkaAndRepaint(Location location) {
        Location ringFigurka = getRingFigurka();
        if (location.isNull()) {
            // pripad kdy byla drive oznacena figurka, ale ted sme vyjeli z sachovnice. Figurku musime odoznacit
            if (!ringFigurka.isNull()) {
                getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                ringFigurka.setNull();
                getChessPane().repaint();
            }
        } else {
            // figurka na kterou jsme najeli se nerovna stare, takze musime prekreslovat
            if (!ringFigurka.equals(location)) {
                Figurka fig = getChessGame().getSachovnice().getFigurka(location.getX(), location.getY());
                // najel jsem na figurku sve barvy
                if (((fig.getColor() == 2) && (getChessGame().isMeWhite())) || ((fig.getColor() == 1) && (!getChessGame().isMeWhite()))) {
                    if (!ringFigurka.isNull()) {
                        getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                    }
                    setRingFigurka(location);
                    fig.setRing(true);
                    getChessPane().repaint();
                } else {
                    // vyjel jsem z figurky sve barvy na nekterou jinou barvu
                    if (!ringFigurka.isNull()) {
                        getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                        ringFigurka.setNull();
                        getChessPane().repaint();
                    }
                }
            }
        }
    }

    // nastava pri stisku na figurku nasi barvy. Muze ale nastat jen pokud jsme
    // na tahu a nebyla oznacena jina figurka pro tah.
    // Po kontrole jestli jsme stiskli na nasi figurku s prstencem se na figurce nastavi markForPlay
    // (zaroven s tim, by se markForPlay melo poslat zrejme i souperi....TODO)
    // TODO - Zatim to umoznuje zrusit vybranou figurku, ale to by do budoucna nemelo.
    // (V sachach totiz pri zvednuti figurky s ni hrac musi hrat)
    public void selectFigurkaForPlay(Location location) {
    	Location ringFigurka = getRingFigurka();
        if ((!location.isNull()) && (location.equals(ringFigurka))) {
            if (!isMarked()) {
                setMarked(true);
                Figurka fig = getChessGame().getSachovnice().getFigurka(location.getX(), location.getY());
                fig.setRing(false);
                fig.setMarked(true);
                ringFigurka.setNull();
                setMarkedFigurkaForPlay(location);
                getChessPane().repaint();
            }
        }
    }

    // zpusobi odoznaceni figurky, ktera byla puvodne oznacena pro hru.
    public void deselectFigurkaSelectedForPlay(Location location) {
    	Location markedFigurkaForPlay = getMarkedFigurkaForPlay();
        if ((!location.isNull()) && (location.equals(markedFigurkaForPlay))) {
            setMarked(false);
            Figurka fig = getChessGame().getSachovnice().getFigurka(location.getX(), location.getY());
            fig.setRing(true);
            fig.setMarked(false);
            markedFigurkaForPlay.setNull();
            setRingFigurka(location);
            getChessPane().repaint();
        }
    }

    // zpusobi odehrani tahu a poslani tohoto tahu protihraci.
    // nutna podminka: mame oznacenu figurku a misto nad kterym prave stojime je oprstencovane
    public void play(Location location) {
    	Location ringFigurka = getRingFigurka();
    	Location markedFigurkaForPlay = getMarkedFigurkaForPlay();
        if ((!location.isNull()) && (location.equals(ringFigurka)) && (!markedFigurkaForPlay.isNull())) {
            Figurka fig = getChessGame().getSachovnice().getFigurka(markedFigurkaForPlay.getX(), markedFigurkaForPlay.getY());
            fig.setRing(false);
            fig.setMarked(false);
            setMarked(false);
            markedFigurkaForPlay.setNull();
            int newX = ringFigurka.getX();
            int newY = ringFigurka.getY();
            int oldX = fig.getX();
            int oldY = fig.getY();                        
            NastaveniShowPanel.getConnectThread().sendToServer("PLAY: _"  + oldX + "_" + oldY + "_" + newX + "_" + newY);
            doPlay(oldX, oldY, newX, newY);
            
            // kontrola jestli pesec nedosel na posledni pole
            if (fig instanceof Pesec) { 
                //NastaveniShowPanel.getConnectThread().sendToServer("PESEC_DOSEL: ");
                //PesecNaKonciDialog.getInstance(1, newX, newY);
                if ((getChessGame().isMeWhite()) && (newY == 0)) {
                    NastaveniShowPanel.getConnectThread().sendToServer("PESEC_DOSEL: ");
                    PesecNaKonciDialog.getInstance(2, newX, newY);
                }
                else if ((!getChessGame().isMeWhite()) && (newY == 7)) {
                    NastaveniShowPanel.getConnectThread().sendToServer("PESEC_DOSEL: ");
                    PesecNaKonciDialog.getInstance(1, newX, newY);
                }
            }                                         
        }
    }

    // prime odehrani tahu bez kontrol markupu a ringu atd. Tato metoda je volana
    // u aktivniho hrace i u protihrace (po tom co obdrzi muj tah ze serveru)
    public void doPlay(int oldX, int oldY, int newX, int newY) {
        doPlayImpl(oldX, oldY, newX, newY, true);
    }
    
    // implementuje doPlay. Priznak newTahFlag indikuje, zda je metoda volana z doPlay (coz nastava skoro vzdy)
    // nebo rekurzivne (tahy rosada a en-passant)
    private void doPlayImpl(int oldX, int oldY, int newX, int newY, boolean newTahFlag) {
    	super.doPlay(oldX, oldY, newX, newY);
    	if (newTahFlag) {
    	     getChessPane().postupneZmizniFigurku(oldX, oldY);
   	         // nastaveni figurky, ktera se nebude prekreslovat. Bude nakreslena stara
   	         getChessPane().setDontPaintOldFigurka(getChessGame().getSachovnice().getFigurka(newX, newY));
   	         getChessPane().setDontPaintLocation(new Location(newX, newY));
    	}
        Figurka fig = getChessGame().getSachovnice().getFigurka(oldX, oldY);
        ChessPole sachovnice = fig.getSachovnice();
        
        sachovnice.setFigurka(newX, newY, fig);
        fig.setX(newX);
        fig.setY(newY);
        Prazdna prazdnePole = new Prazdna(oldX, oldY, sachovnice);
        sachovnice.setFigurka(oldX, oldY, prazdnePole);

        if (fig instanceof King) {
            //System.out.println("FIG INSTANCE OF KING newX:" + newX + " newY:" + newY);
            if (fig.getColor() == 1) {
                getChessGame().getSachovnice().setBlackKingLocation(new Location(newX, newY));
            } else {
                getChessGame().getSachovnice().setWhiteKingLocation(new Location(newX, newY));
            }
        }                
        // kontrola a provedeni rosady        
        if ((fig instanceof King) && (!fig.isOdehralTah())) {
        	// spoustime rekurzivne doPlay, takze musime prenastavit isWhiteNaTahu        	
            if ((fig.getColor() == 2) && (newX == 6)) { 
            	doPlayImpl(7, 7, 5, 7, false);
            	getGame().setWhiteNaTahu(!this.getGame().isWhiteNaTahu());  
            }
            if ((fig.getColor() == 2) && (newX == 2)) {
            	doPlayImpl(0, 7, 3, 7, false);
            	getGame().setWhiteNaTahu(!this.getGame().isWhiteNaTahu());  
            }
            if ((fig.getColor() == 1) && (newX == 6)) {
            	doPlayImpl(7, 0, 5, 0, false);
            	getGame().setWhiteNaTahu(!this.getGame().isWhiteNaTahu());  
            }
            if ((fig.getColor() == 1) && (newX == 2)) {
            	doPlayImpl(0, 0, 3, 0, false);
            	getGame().setWhiteNaTahu(!this.getGame().isWhiteNaTahu());  
            }
        }
        fig.setOdehralTah(true);
        //
        // nastaveni last tahu kvuli en passant a provedeni nasledujiciho tahu po en passant
        getChessGame().getSachovnice().setLastTah(oldX, oldY, newX, newY);        
        if ((fig instanceof Pesec) && (oldY == newY)) {
        	// spoustime rekurzivne doPlayImpl, takze musime prenastavit isWhiteNaTahu
        	getGame().setWhiteNaTahu(!this.getGame().isWhiteNaTahu());          	
            if (fig.getColor() == 1) {
            	doPlayImpl(newX, newY, newX, newY + 1, false);
            }
            else {
            	doPlayImpl(newX, newY, newX, newY - 1, false);
            }
        }
        if (newTahFlag) {
            getChessPane().postupneObjevFigurku(newX, newY);
        }
        getLastTahLabel().setText(Text.getLastTahMessage(fig.getFigurkaName(), oldX, oldY, newX, newY));
        //getChessPane().postupneZmizniFigurku(oldX, oldY);                
        // kontrola sachu
        controlSach(fig);     	
    }
    
    // metoda zkontroluje jestli je sach kterekoliv barvy a pokud ano, tak aktualizuje labely
    // a vola kontrolu sach matu. Metoda vraci true pokud sach nastal.
    public boolean controlSach(Figurka fig) {
        // kontrola sachu
        if (getChessGame().getSachovnice().isSach(1, getChessGame().getSachovnice().getBlackKingLocation().getX(), getChessGame().getSachovnice().getBlackKingLocation().getY())) {
            //System.out.println("BLACK MA SACH");
            getSachLabel().setText(addHtmlTagsToLabels(Text.getSachLabelText(getChessGame().getBlackPlayerName()), "RED", '3'));            
            if (getChessGame().getSachovnice().isSachMat(1, getChessGame().getSachovnice().getBlackKingLocation().getX(), getChessGame().getSachovnice().getBlackKingLocation().getY(), fig)) { 
                getSachLabel().setText(addHtmlTagsToLabels(Text.getSachMatLabelText(getChessGame().getBlackPlayerName()), "RED", '3'));            
                this.setActiveToGame(false);
                if (getChessGame().isMeWhite()) {
                    setEndStateToGame(true);
                    SimpleDialog.getInstance(PropertiesManager.getInstance().getMessageForKey(Text.VYHRA), PropertiesManager.getInstance().getMessageForKey(Text.MAT_VYHRA_MESSAGE));
                }
                else {
                    setEndStateToGame(true);
                    SimpleDialog.getInstance(PropertiesManager.getInstance().getMessageForKey(Text.PROHRA), PropertiesManager.getInstance().getMessageForKey(Text.MAT_PROHRA_MESSAGE));
                }                
                //System.out.println("CERNEJ MA SACH MAT.");
            }
            return true;
        } else if (getChessGame().getSachovnice().isSach(2, getChessGame().getSachovnice().getWhiteKingLocation().getX(), getChessGame().getSachovnice().getWhiteKingLocation().getY())) {
            //System.out.println("WHITE MA SACH");
            getSachLabel().setText(addHtmlTagsToLabels(Text.getSachLabelText(getChessGame().getWhitePlayerName()), "RED", '3'));
            if (getChessGame().getSachovnice().isSachMat(2, getChessGame().getSachovnice().getWhiteKingLocation().getX(), getChessGame().getSachovnice().getWhiteKingLocation().getY(), fig)) { 
                getSachLabel().setText(addHtmlTagsToLabels(Text.getSachMatLabelText(getChessGame().getWhitePlayerName()), "RED", '3'));            
                this.setActiveToGame(false);
                if (!getChessGame().isMeWhite()) {
                    setEndStateToGame(true);
                    SimpleDialog.getInstance(PropertiesManager.getInstance().getMessageForKey(Text.VYHRA), PropertiesManager.getInstance().getMessageForKey(Text.MAT_VYHRA_MESSAGE));
                }
                else {
                    setEndStateToGame(true);
                    SimpleDialog.getInstance(PropertiesManager.getInstance().getMessageForKey(Text.PROHRA), PropertiesManager.getInstance().getMessageForKey(Text.MAT_PROHRA_MESSAGE));
                }                
                //System.out.println("BILEJ MA SACH MAT.");
            }
            return true;
        } else {
            getSachLabel().setText("");
            return false;
        }
    }

    // nastava pokud uz sme oznacili figurku pro hru a jezdime na sachovnici.
    // cervene se obarvuji mista, kam figurka muze jet. Zaroven s tim se obarvuje priznak ring
    // na techto mistech
    public void updateRingForPlaceWhereFigurkaCanPlay(Location location) {
        if (location.isNull()) {
        	Location ringFigurka = getRingFigurka();
            // pripad kdy byla drive oznacena figurka, ale ted sme vyjeli z sachovnice. Figurku musime odoznacit
            if (!ringFigurka.isNull()) {
                getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                ringFigurka.setNull();
                getChessPane().repaint();
            }
        } else {
            // figurka na kterou jsme najeli se nerovna stare, takze musime prekreslovat
        	Location ringFigurka = getRingFigurka();
            if (!ringFigurka.equals(location)) {
                Figurka fig = getChessGame().getSachovnice().getFigurka(location.getX(), location.getY());
                Figurka markedFig = getChessGame().getSachovnice().getFigurka(getMarkedFigurkaForPlay().getX(), getMarkedFigurkaForPlay().getY());
                // pripad kdy zvolena figurka muze tahnout na vybrane pole
                if (markedFig.muzeTahnout(location.getX(), location.getY())) {
                    if (!ringFigurka.isNull()) {
                        getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                    }
                    setRingFigurka(location);
                    fig.setRing(true);
                    getChessPane().repaint();
                } else {
                    if (!ringFigurka.isNull()) {
                        getChessGame().getSachovnice().getFigurka(ringFigurka.getX(), ringFigurka.getY()).setRing(false);
                        ringFigurka.setNull();
                        getChessPane().repaint();
                    }
                }

                
            }
        }
    }
    
    // metoda zkontroluje jestli je sach jakekoliv barvy. Pokud ano, tak aktualizuje labely.
    public void controlSachForEveryFigurka() {
        for (int i=0 ; i<8 ; i++) 
             for (int j=0 ; j<8 ; j++) {
                 Figurka fig = getChessGame().getSachovnice().getFigurka(i, j);
                 if (controlSach(fig)) return;
             }        
    }
    
    // nastavi figurku podle toho, co doslo z pesec dialogu nebo od oponenta ze serveru   
    public Figurka setFigurkaFromPesecDosel(String figClass, int x, int y, int color) {    
    	Figurka fig = getChessGame().getSachovnice().setFigurkaFromPesecDosel(figClass, x, y, color);
    	getChessPane().repaint();
    	return fig;
    }        
    
    // nastavi active u hry a provede pridruzene akce
    public void setActiveToGame(boolean active) {    	    	
        for (int i=0 ; i<8 ; i++) 
            for (int j=0 ; j<8 ; j++) {
                Figurka fig = getChessGame().getSachovnice().getFigurka(i, j);
                fig.setRing(false);
                fig.setMarked(false);
            }       
        super.setActiveToGame(active);
    } 
    
    // volani specialnich udalosti - viz. predek
    public void performSpecialEvent(int eventId, String eventString) {
    	if (eventId == GamePanel.EVENT_CHESS_PESEC_DOSEL) {
    		performEventPesecDosel(eventString);
    	}
    	else if (eventId == GamePanel.EVENT_CHESS_VYBRANA_FIGURKA) {
    		performEventVybranaFigurka(eventString);
    	}
    }
    
    // zavolano kdyz doslo ze serveru, ze protivnikuv pesec dosel do cile
    private void performEventPesecDosel(String eventString) {
       	getGame().setWhiteNaTahu(!getGame().isWhiteNaTahu());
    	getSachLabel().setText("<HTML><BODY><FONT COLOR=RED SIZE=3>" + PropertiesManager.getInstance().getMessageForKey(Text.PROTIVNIK_VYBIRA) + "</FONT></BODY></HTML>");
    	getVrchniLabel().setText(Text.getPlayerNaTahu(getGame().getOpponentName()));    	
    }
    
    private void performEventVybranaFigurka(String eventString) {
    	getGame().setWhiteNaTahu(!getGame().isWhiteNaTahu());
    	getVrchniLabel().setText(Text.getPlayerNaTahu(getGame().getMyName()));
        int xx = Integer.parseInt(eventString.substring(17, 18));
        int yy = Integer.parseInt(eventString.substring(18, 19));
        int col = Integer.parseInt(eventString.substring(19, 20));
        String figType = eventString.substring(20);
        Figurka fig = setFigurkaFromPesecDosel(figType, xx, yy, col);
        controlSach(fig);    	
    }
    
}
